package com.fang.dubbo.mock.spi.filter;

import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.extension.Activate;
import com.alibaba.dubbo.rpc.*;
import com.fang.dubbo.mock.common.TraceLogUtils;
import lombok.extern.slf4j.Slf4j;

/**
 * @author fanglingxiao
 * @version 1.0
 * @description TODO
 * @date 2022/1/3 2:38 下午
 **/
@Slf4j
@Activate(Constants.PROVIDER)
public class ProviderFilter implements Filter {
    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        long start = System.currentTimeMillis();
        Result result;
        String status = "success";
        try {
            //把上游的traceid 写入本地线程中 如果没有则生成一个新的
            String traceId = RpcContext.getContext().getAttachment("traceId");
            TraceLogUtils.genTraceId(traceId);
            // 调用
            result = invoker.invoke(invocation);

            if (result.hasException()) {
                status = result.getException().getClass().getSimpleName();
                throw result.getException();
            }
            return result;
        } catch (Throwable e) {
            log.error("rpc Provider调用异常", e);
            status = "error";
            if (e instanceof RpcException) {
                RpcException rpcEx = (RpcException) e;
                if (rpcEx.isTimeout()) {
                    status = "timeoutError";
                }
                if (rpcEx.isBiz()) {
                    status = "bisError";
                }
                if (rpcEx.isNetwork()) {
                    status = "networkError";
                }
                if (rpcEx.isSerialization()) {
                    status = "serializationError";
                }
                // end
                throw (RpcException) e;
            }
            throw new RpcException(e);


        } finally {
            long callTime = System.currentTimeMillis() - start;
            String serviceName = invoker.getInterface().getSimpleName() + "." + invocation.getMethodName();
            //
            log.info("call={};useTime={};status={}", serviceName, callTime, status);
        }
    }
}
